#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>


void read_cb(struct bufferevent *bev, void *arg)
{
    char buf[1024] = {0}; 
    bufferevent_read(bev, buf, sizeof(buf));
    printf("Server say: %s\n", buf);
}

void write_cb(struct bufferevent *bev, void *arg)
{
    printf("I am Write_cb function....\n");
}

void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
        printf("connection closed\n");  
    }
    else if(events & BEV_EVENT_ERROR)   
    {
        printf("some other error\n");
    }
    else if(events & BEV_EVENT_CONNECTED)
    {
        printf("成功连接到服务器, O(∩_∩)O哈哈~\n");
        return;
    }
    
    bufferevent_free(bev);
    printf("free bufferevent...\n");
}

void read_terminal(evutil_socket_t fd, short what, void *arg)
{
    //这个fd是 stdin 监听键盘输入
    char buf[1024] = {0}; 
   
  //  printf("请输入要发送的数据: \n");
    read(fd, buf, sizeof(buf));

    struct bufferevent* bev = (struct bufferevent*)arg;
    bufferevent_write(bev, buf, strlen(buf)+1);
}


int main(int argc, const char* argv[])
{
    struct event_base* base;
    base = event_base_new();


// 用于通信的文件描述符
    struct bufferevent* bev;
    /**  参数1： event_base
     *  参数2：  evutil_socket_t fd , 文件描述符 
     * 参数3：  
     *BEV_OPT_CLOSE_ON_FREE :释放 buferevent时关闭底层传输端口。这称关闭底层套接字，释放底层 bufferevent 等，、

     可以使用 bufferevent socket new()创建基于套接字的 bufferevent
     */ 
    bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    // 连接服务器
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    evutil_inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));

    // 设置读取回调
    /**
     * bufferevent_setcb(
     struct bufferevent *bufev,
bufferevent_data_cb readcb,    //读回调
bufferevent_data_cb writecb,     // 写回调  
bufferevent_event_cb eventcb,     //连接回调
void *cbarg
)
*/
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    //bufferevent_disable(struct bufferevent *bufev, short event); 禁止调某个事件
    //开启读, 读缓存区才可使用 ， 默认写可用不用设置 
    bufferevent_enable(bev, EV_READ | EV_PERSIST);

    // 创建一个stdin输入事件监听， 持续监听 
    /**
     * event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *
     *  传递 bev 用于发送键盘输入数据发给服务器
     */
    struct event* ev = event_new(base, STDIN_FILENO, 
                                 EV_READ | EV_PERSIST, 
                                 read_terminal, bev);
    event_add(ev, NULL);
    
    event_base_dispatch(base);

    event_base_free(base);

    return 0;
}
